import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

class AutoscrollViewport extends JViewport {
	Point scrollTo = new Point(), last = new Point();
	boolean manualDragUnderway = false;
	final int increment;

	public AutoscrollViewport(Component component, int inc) {
		this.increment = inc;

		setView(component);

		setAutoscrolls(true);
		setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));

		addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				last.x = e.getPoint().x;
				last.y = e.getPoint().y;
				manualDragUnderway = true;
			}
		});	
		addMouseMotionListener(new MouseMotionAdapter() {
			public void mouseDragged(MouseEvent e) {
				Point drag = e.getPoint();
				Point viewPos = getViewPosition();
				Point offset = new Point(drag.x - last.x,
											drag.y - last.y);
				last.x = drag.x;
				last.y = drag.y;

				if(contains(drag)) {
					if(manualDragUnderway) {
						scrollTo.x = viewPos.x - offset.x;
						scrollTo.y = viewPos.y - offset.y;
						setViewPosition(scrollTo);
					}
				}
				else {  // autoscrolling ...
					Rectangle bounds = getBounds();

					manualDragUnderway = false;

					if(drag.x > bounds.x + bounds.width) {
						// scroll right
						viewPos.x -= increment;
						setViewPosition(viewPos);
					}
					if(drag.x < 0) {
						// scroll left
						viewPos.x += increment;
						setViewPosition(viewPos);
					}
					if(drag.y > bounds.y + bounds.height) {
						// scroll down
						viewPos.y -= increment;
						setViewPosition(viewPos);
					}
					if(drag.y < 0) {
						// scroll up
						viewPos.y += increment;
						setViewPosition(viewPos);
					}
				}
			}
		});
	}
}
